package project.parser.ast.exps.op.binary;

import project.environments.DynamicEnv;
import project.environments.StaticEnv;
import project.environments.Value;
import project.parser.EvalException;
import project.parser.ast.exps.Exp;
import project.parser.ast.types.PrimType;
import project.parser.ast.types.Type;
import project.parser.ast.util.EvalUtil;
import project.parser.ast.util.TypecheckUtil;
import project.parser.ast.values.BoolValue;
import project.parser.ast.values.RecordValue;

public abstract class EqualOp extends BinaryOp {
	public EqualOp(Exp left, Exp right) {
		super(left, right);
	}

	@Override
	public Type typecheck(StaticEnv senv) {
		return TypecheckUtil.checkEqualOp(senv, left, right);
	}

	@Override
	public Value evaluate(DynamicEnv denv) {
		Value leftValue = left.evaluate(denv);
		Type leftType = leftValue.type();
		if (leftType instanceof PrimType)
			switch ((PrimType)leftType) {
				case NUMBER_TYPE:
					int rightIntValue = EvalUtil.evalIntArg(denv, right);
					return new BoolValue(op(leftValue.asInteger(), rightIntValue));
				case BOOLEAN_TYPE:
					boolean rightBoolValue = EvalUtil.evalBoolArg(denv, right);
					return new BoolValue(op(leftValue.asBoolean(), rightBoolValue));
				default:
					throw new EvalException("Error in equal expression");
			}
		else {
			Value rightValue = right.evaluate(denv);
			if (RecordValue.isInstance(rightValue))
				return new BoolValue(op(leftValue, rightValue));
			else
				throw new EvalException("Error in equal expression");
		}
	}

	abstract protected boolean op(int left, int right);

	abstract protected boolean op(boolean left, boolean right);

	abstract protected boolean op(Value left, Value right);

	@Override
	public String toString() {
		return left.toString() + opToString() + right.toString();
	}
}
